﻿using ArtMath.CommonType;
using ArtMath.Component;
using ArtMath.Component.Line;
using ArtMath.Flag;
using ArtMath.Parameter;
using ArtMath.Resource;
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.IO;
using System.Reflection;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Windows.Forms;

namespace ArtMath.Setting
{
    [Serializable]
    public class Settings
    {
        static readonly string SettingsSavePath = Application.StartupPath + "\\configuration.cfg";
        //static Settings instance;
        public static Settings Instance { get; set; }
        //{
        //    get { return instance; }
        //    set { instance = value; }
        //}
        public string Language;
        public FillStyle ClosedShapeFillStyle;
        public UIColorTheme ColorTheme;
        public bool SectorShowFullCircle;
        public bool AutoFixAbsorbedPoints;
        public bool ManagerAutoDelete;
        [SettingDisplayName(null, false, "Show", "Track")]
        public bool ShowTrack;
        public bool FitSize;
        [SettingDisplayName("RecordTrack")]
        public bool Track;
        public bool ManagerAutoAdd;
        [SettingDisplayName(null, false, "Show", "Border")]
        public bool ShowBorder;
        public bool AnimateOnOneCurve;
        public bool FixOnConnectedLineGroup;
        public bool DisableReversedColorWhenEqualsPadBGColor;
        [InVisible]
        public bool RealTimeTransform;
        public bool SelfRotate;
        public bool AutoReduceAccuracy;
        public bool CheckExtension;
        public bool CloseHomePageAfterDocumentLoaded;
        public bool ShowHomePageAfterStartup;
        [SettingDisplayName("Transform")]
        public bool TransformUseFormat;
        [SettingDisplayName("Appearance")]
        public bool AppearanceUseFormat;
        [SettingDisplayName(null, false, "Property", "Displayer")]
        public bool PropertyDisplayerUseFormat;
        [SettingDisplayName("Track")]
        public bool TrackUseFormat;
        [SettingDisplayName("View")]
        public bool ViewUseFormat;
        [SettingDisplayName("Layout")]
        public bool LayoutUseFormat;
        [SettingDisplayName("InChildren")]
        public bool InChildrenUseFormat;
        [InVisible]
        public bool ShowOtherPadParameters;
        [InVisible]
        public bool ShowOtherPadRecycleItems;
        [Range(10, 50), Unit("px")]
        public int LayerItemHeight;
        [Range(0, 3600), Unit("s")]
        public int AutoSaveInterval;
        [InVisible]
        public float TransformSaturationOffset;
        public double VirtualLineWidth;
        [SettingDisplayName("Of", true, "Ring", "Radius")]
        public double RingRadius;
        [SettingDisplayName("Of", true, "Circle", "Accuracy")]
        public double CircleAccuracy;
        public double PointAbsorb;
        [SettingDisplayName("Of", true, "PointEraser", "Radius")]
        public double PointEraserRadius;
        [SettingDisplayName("Of", true, "Hyperbola", "Accuracy")]
        public double HyperbolaAccuracy;
        public double PointEPS;
        public double NumberREPS;
        public double NumberEPS;
        [SettingDisplayName("Of", true, "Parabola", "Accuracy")]
        public double ParabolaAccuracy;
        [SettingDisplayName("Of", true, "RCFunction", "Accuracy")]
        public double RCFunctionAccuracy;
        [SettingDisplayName("Of", true, "Ellipse", "Accuracy")]
        public double EllipseAccuracy;
        public double VirtualPointOutlineWidth;
        public double VirtualPointSize;
        public double LineAbsorb;
        public double ZoomDelta;
        public double VerticalScrollDistance;
        public double HorizontalScrollDistance;
        [SettingDisplayName("Of", true, "WinDocuments", "HeightWeight"), Unit("%")]
        public double WinDocumentsHeight;
        [SettingDisplayName("Of", true, "WinParameters", "HeightWeight"), Unit("%")]
        public double WinParametersHeight;
        [SettingDisplayName("Of", true, "ToolBox", "HeightWeight"), Unit("%")]
        public double WinToolsHeight;
        [SettingDisplayName("Of", true, "WinAnimations", "HeightWeight"), Unit("%")]
        public double WinAnimationsHeight;
        [SettingDisplayName("Of", true, "WinComponents", "HeightWeight"), Unit("%")]
        public double WinComponentsHeight;
        [SettingDisplayName("Of", true, "Property", "HeightWeight"), Unit("%")]
        public double WinPropertiesHeight;
        [SettingDisplayName("Of", true, "PCFunction", "Accuracy")]
        public double PCFunctionAccuracy;
        public FunctionAbsorbRule FunctionAbsorbPolicy;
        [Unit("ms"), Range(0, 1000)]
        public int FlashInterval;
        public ParameterUnit ParamUnit;
        [SettingDisplayName("LinearGradientAngle")]
        public string ClosedShapeLinearAngle;
        public string LineWidth;
        [SettingDisplayName(null, false, "Border", "Thickness")]
        public string BorderWidth;
        public string AxisScale;
        public string HighlighterPenLen;
        public string TrackWidth;
        [SettingDisplayName("RayInterval")]
        public string PolarAxisBeamScale;
        [SettingDisplayName("Of", true, "Point", "OutlineWidth")]
        public string PointOutlineWidth;
        [SettingDisplayName("Of", true, "Point", "Size")]
        public string PointSize;
        public string BallPenSize;
        public double CopyOffset_WithoutCS_Width;
        public double CopyOffset_WithoutCS_Height;
        public double CopyOffset_WithCS_Width;
        public double CopyOffset_WithCS_Height;
        [SettingDisplayName(null, false, "ClosedShape", "LinearGradientEndColor")]
        public Color LinearGradientEndColor;
        [SettingDisplayName(null, false, "Point", "OutlineColor")]
        public Color PointOutlineColor;
        public Color LineColor;
        [SettingDisplayName(null, false, "CrossoverPoint", "OutlineColor")]
        public Color CrossoverPointOutlineColor;
        [SettingDisplayName(null, false, "ClosedShape", "LinearGradientStartColor")]
        public Color LinearGradientStartColor;
        [SettingDisplayName("{0}/{1}+{2}", false, "RectangularCoordinateOrigin", "PolarCoordinateOrigin", "OutlineColor")]
        public Color OriginPointOutlineColor;
        [SettingDisplayName(null, false, "OrthoCenter", "OutlineColor")]
        public Color OrthoCenterPointOutlineColor;
        [SettingDisplayName(null, false, "CircumCenter", "FillColor")]
        public Color CircumCenterFillColor;
        [SettingDisplayName(null, false, "ClosedShape", "FillColor")]
        public Color ClosedShapeFillColor;
        [SettingDisplayName(null, false, "Shape", "Center", "OutlineColor")]
        public Color ShapeCenterPointOutlineColor;
        [SettingDisplayName(null, false, "CrossoverPoint", "FillColor")]
        public Color CrossoverPointFillColor;
        [SettingDisplayName(null, false, "BaryCenter", "FillColor")]
        public Color BaryCenterPointFillColor;
        [SettingDisplayName(null, false, "Point", "FillColor")]
        public Color PointFillColor;
        [SettingDisplayName(null, false, "CoordinateAxis", "Color")]
        public Color AxisColor;
        [SettingDisplayName(null, false, "CoordinateSystem", "Grid", "Color")]
        public Color AxisGridColor;
        [SettingDisplayName(null, false, "DefiniteProportionateInsertedPoint", "FillColor")]
        public Color ProportionatePointFillColor;
        [SettingDisplayName(null, false, "DefiniteProportionateInsertedPoint", "OutlineColor")]
        public Color ProportionatePointOutlineColor;
        [SettingDisplayName(null, false, "Shape", "Center", "FillColor")]
        public Color ShapeCenterFillColor;
        [SettingDisplayName(null, false, "BaryCenter", "OutlineColor")]
        public Color BaryCenterPointOutlineColor;
        [SettingDisplayName(null, false, "Border", "Color"), NonTransparent]
        public Color BorderColor;
        [SettingDisplayName(null, false, "Track", "Color")]
        public Color TrackColor;
        [SettingDisplayName(null, false, "Text", "Color")]
        public Color TextColor;
        [SettingDisplayName(null, false, "CoordinateSystem", "Graduation", "Color")]
        public Color AxisRulerColor;
        [SettingDisplayName(null, false, "Virtual", "Point", "OutlineColor")]
        public Color VirtualPointOutlineColor;
        [SettingDisplayName(null, false, "Virtual", "Point", "FillColor")]
        public Color VirtualPointFillColor;
        [SettingDisplayName(null, false, "CoordinatePoint", "FillColor")]
        public Color FixedPointFillColor;
        [SettingDisplayName(null, false, "CoordinateSystem", "GraduationText", "Color")]
        public Color AxisTextColor;
        [SettingDisplayName(null, false, "Virtual", "ClosedShape", "FillColor")]
        public Color VirtualClosedShapeFillColor;
        [SettingDisplayName(null, false, "CircumCenter", "OutlineColor")]
        public Color CircumCenterOutlineColor;
        [SettingDisplayName(null, false, "CoordinatePoint", "OutlineColor")]
        public Color FixedPointOutlineColor;
        [SettingDisplayName(null, false, "InCenter", "OutlineColor")]
        public Color IncenterPointOutlineColor;
        [SettingDisplayName(null, false, "Function", "Color")]
        public Color FunctionColor;
        [SettingDisplayName(null, false, "OrthoCenter", "FillColor")]
        public Color OrthoCenterPointFillColor;
        [SettingDisplayName(null, false, "Virtual", "LineColor")]
        public Color VirtualLineColor;
        [SettingDisplayName(null, false, "InCenter", "FillColor")]
        public Color IncenterPointFillColor;
        [SettingDisplayName(null, false, "Text", "Background", "Color")]
        public Color TextBackgroundColor;
        public ContentAlignment TextAlignment;
        public DashStyle VirtualLineDashStyle;
        [SettingDisplayName("LineDashStyle")]
        public DashStyle LineDashStyle;
        public DashStyle BorderDashStyle;
        [SettingDisplayName("QualityMode")]
        public SmoothingMode PictureQuality;
        public GeneralCurveTangentSlopeSolution GeneralCurveTangentSlopeSolution;
        public TabAlignment TabLocation;
        [SettingDisplayName(null, false, "Text", "Font")]
        public Font TextFont;
        [SettingDisplayName(null, false, "Parameter", "Font")]
        public Font ParamFont;
        [SettingDisplayName(null, false, "Property", "Displayer", "Font")]
        public Font PropertyDisplayerFont;
        static Settings()
        {
            IFormatter fmt = new BinaryFormatter();
            try
            {
                Stream stream = new FileStream(SettingsSavePath, FileMode.Open, FileAccess.Read, FileShare.None);
                Instance = fmt.Deserialize(stream) as Settings;
                stream.Close();
            }
            catch (Exception)
            {
                Instance = new Settings();
            }
        }
        Settings()
        {
            Reset();
        }
        public void Reset()
        {
            Language = "zh-CN";
            ColorTheme = UIColorTheme.Blue;
            ClosedShapeFillStyle = FillStyle.SolidColor;
            AutoFixAbsorbedPoints = ManagerAutoDelete = ShowTrack = FitSize = ManagerAutoAdd = ShowBorder = AutoReduceAccuracy =
                FixOnConnectedLineGroup = DisableReversedColorWhenEqualsPadBGColor = ShowOtherPadParameters = CheckExtension =
                TransformUseFormat = AppearanceUseFormat = PropertyDisplayerUseFormat = TrackUseFormat = SelfRotate = 
                ViewUseFormat = InChildrenUseFormat = SectorShowFullCircle = LayoutUseFormat = RealTimeTransform =
                ShowHomePageAfterStartup = CloseHomePageAfterDocumentLoaded = true;
            Track = AnimateOnOneCurve = ShowOtherPadRecycleItems = false;
            LayerItemHeight = 25;
            RingRadius = 30;
            TransformSaturationOffset = 0.2f;
            WinDocumentsHeight = WinParametersHeight = 17.5;
            WinToolsHeight = 65;
            WinAnimationsHeight = 24;
            WinComponentsHeight = 36;
            WinPropertiesHeight = 40;
            VerticalScrollDistance = HorizontalScrollDistance = 50;
            VirtualLineWidth = VirtualPointOutlineWidth = 3;
            EllipseAccuracy = RCFunctionAccuracy = 50;
            CircleAccuracy = PCFunctionAccuracy = 100;
            PointAbsorb = PointEraserRadius = LineAbsorb = 10;
            HyperbolaAccuracy = ParabolaAccuracy = 500;
            AutoSaveInterval = 300;
            PointEPS = NumberEPS = 1e-6;
            NumberREPS = 1e-4;
            VirtualPointSize = 5;
            ZoomDelta = 0.5;
            FunctionAbsorbPolicy = FunctionAbsorbRule.GetNearestPoint;
            FlashInterval = 700;
            ParamUnit = ParameterUnit.None;
            ClosedShapeLinearAngle = "0";
            LineWidth = TrackWidth = PointOutlineWidth = BallPenSize = "3";
            BorderWidth = "1";
            AxisScale = "50";
            HighlighterPenLen = PolarAxisBeamScale = "30";
            PointSize = "5";
            LinearGradientEndColor = Color.LightGreen;
            PointOutlineColor = LineColor = Color.Blue;
            CrossoverPointOutlineColor = Color.FromArgb(175, 95, 60);
            LinearGradientStartColor = Color.LightBlue;
            OriginPointOutlineColor = AxisRulerColor = Color.FromArgb(237, 125, 49);
            BorderColor = TextColor = AxisTextColor = Color.Black;
            OrthoCenterPointOutlineColor = Color.FromArgb(255, 196, 8);
            CircumCenterFillColor = Color.Lime;
            ClosedShapeFillColor = VirtualClosedShapeFillColor = Color.Transparent;
            ShapeCenterPointOutlineColor = Color.FromArgb(255, 192, 0);
            CrossoverPointFillColor = Color.FromArgb(251, 150, 110);
            BaryCenterPointFillColor = Color.FromArgb(225, 107, 140);
            PointFillColor = Color.Red;
            AxisColor = Color.FromArgb(237, 125, 49);
            AxisGridColor = Color.LightGray;
            ProportionatePointFillColor = Color.FromArgb(234, 239, 247);
            ProportionatePointOutlineColor = Color.FromArgb(91, 155, 213);
            ShapeCenterFillColor = Color.FromArgb(255, 244, 231);
            BaryCenterPointOutlineColor = Color.FromArgb(142, 53, 74);
            TrackColor = FunctionColor = Color.Magenta;
            VirtualPointOutlineColor = VirtualLineColor = Color.FromArgb(100, 0, 0, 255);
            VirtualPointFillColor = Color.FromArgb(100, 255, 0, 0);
            FixedPointFillColor = Color.FromArgb(232, 232, 236);
            CircumCenterOutlineColor = Color.FromArgb(0, 192, 0);
            FixedPointOutlineColor = Color.FromArgb(194, 195, 201);
            IncenterPointOutlineColor = Color.FromArgb(145, 173, 112);
            OrthoCenterPointFillColor = Color.FromArgb(246, 197, 85);
            IncenterPointFillColor = Color.FromArgb(181, 202, 160);
            TextBackgroundColor = Color.White;
            TextAlignment = ContentAlignment.TopLeft;
            VirtualLineDashStyle = DashStyle.Dash;
            LineDashStyle = BorderDashStyle = DashStyle.Solid;
            PictureQuality = SmoothingMode.HighQuality;
            GeneralCurveTangentSlopeSolution = GeneralCurveTangentSlopeSolution.PredecessorAndSuccessor;
            TabLocation = TabAlignment.Top;
            TextFont = new Font(SystemFonts.DefaultFont.FontFamily, 16);
            ParamFont = new Font("SimSun", 16, FontStyle.Bold);
            PropertyDisplayerFont = SystemFonts.DefaultFont;
            CopyOffset_WithCS_Width = 1;
            CopyOffset_WithCS_Height = -1;
            CopyOffset_WithoutCS_Width = CopyOffset_WithoutCS_Height = 50;
        }
        public static string GetFieldDisplayName(FieldInfo info)
        {
            object[] objs = info.GetCustomAttributes(typeof(SettingDisplayNameAttribute), true);
            if (objs?.Length > 0)
            {
                return (objs[0] as SettingDisplayNameAttribute).DisplayName;
            }
            return Resources.Translate(info.Name);
        }
        public bool Save()
        {
            return SaveAs(SettingsSavePath);
        }
        public bool SaveAs(string path)
        {
            IFormatter fmt = new BinaryFormatter();
            try
            {
                Stream stream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);
                fmt.Serialize(stream, this);
                stream.Close();
                if (!Directory.Exists(Flags.UpdateDirectoryPath))
                {
                    Directory.CreateDirectory(Flags.UpdateDirectoryPath);
                }
                File.WriteAllText(Path.Combine(Flags.UpdateDirectoryPath, "lang"), Language);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, Resources.Translate("Error"), MessageBoxButtons.OK, MessageBoxIcon.Error);
                return false;
            }
            return true;
        }

        [AttributeUsage(AttributeTargets.Field, Inherited = true, AllowMultiple = false)]
        public sealed class SettingDisplayNameAttribute : Attribute
        {
            string format;
            string[] args;
            public SettingDisplayNameAttribute(string format, bool translate = false, params string[] args)
            {
                this.format = translate ? Resources.Translate(format) : Resources.GetFormatString(format, args.Length);
                this.args = args;
            }
            public SettingDisplayNameAttribute(string displayName) : this(null, false, displayName)
            {

            }
            public string DisplayName
            {
                get { return Resources.GetLocalizedString(format, args); }
            }
        }
        /// <summary>
        /// 指示颜色不能设置为透明色或半透明色（即Alpha值一定是255）
        /// </summary>
        [AttributeUsage(AttributeTargets.Field, Inherited = true, AllowMultiple = false)]
        public sealed class NonTransparentAttribute : Attribute
        {
            
        }
        [AttributeUsage(AttributeTargets.Field, Inherited = true, AllowMultiple = false)]
        public sealed class UnitAttribute : Attribute
        {
            public UnitAttribute(string unit)
            {
                Unit = unit;
            }
            public string Unit { get; }
        }
        /// <summary>
        /// 指示设置项不会在设置窗口中显示
        /// </summary>
        [AttributeUsage(AttributeTargets.Field, Inherited = true, AllowMultiple = false)]
        public sealed class InVisibleAttribute : Attribute
        {

        }
        [AttributeUsage(AttributeTargets.Field, Inherited = true, AllowMultiple = false)]
        public sealed class RangeAttribute : Attribute
        {
            public int Maximum { get; }
            public int Minimum { get; }
            public RangeAttribute(int min, int max)
            {
                Minimum = min;
                Maximum = max;
            }
        }
    }
}